Park Attributes

There are a total of 58,028 parks in the USA Parks dataset. The table below shows the breakdown by type of park space. 85% of the park spaces are owned and maintained by local governments.

knitr::kable(usa_parks %>% 
               st_set_geometry(NULL) %>%
               select(FEATTYPE) %>%
               count(FEATTYPE) %>%
               arrange(-n),
             col.names = c("Type of Park", "Freq."),
             caption = "Count of Parks in the U.S.",
             format.args = list(big.mark = ",")
             )
Count of Parks in the U.S.
Type of Park Freq.
Local park 49,181
State park or forest 4,654
Regional park 2,009
County park 1,326
National park or forest 858
## Projections
usa_parks_prj <- usa_parks %>%
  st_transform(., crs = albersea)
## State fips codes only
state_identifiers <- fips_codes %>%
  select(state:state_name) %>%
  distinct(.)

Parks by Places

# rmarkdown::paged_table(parks_per_places %>% 
#   create_paged_table_view(.) %>%
#   arrange(-parks) 
# )
  # 54,083 parks 

parks_per_places_reactable <- reactable(parks_per_places %>% 
  create_paged_table_view(.) %>%
  arrange(-parks) %>% 
    mutate(total_park_area_sqmi = round(total_park_area_sqmi, digits = 2),
           percent_of_land_area = percent(percent_of_land_area, accuracy = 0.01,
                                                scale = 1, suffix = "%" 
                                                 )
           ) %>%
  rename(Name = "NAME",
         State = "state",
         Parks = "parks", 
         'Area (Sq Mi)' = "total_park_area_sqmi",
         'Percent of Land Cover' = "percent_of_land_area"), 
  searchable = TRUE,
  filterable = TRUE,
  striped = TRUE,
  highlight = TRUE,
  minRows = 10
  )

div(class = "parks_per_places_reactable",
  div(class = "parks_per_places_reactable-header",
      h3(class = "parks_per_places_reactable-title", "Parks by Places"),
     parks_per_places_reactable
  )
)

Parks by Places

## FIND PLACES WITHOUT PARK SPACE
# rmarkdown::paged_table(places %>% 
#   filter(!GEOID %in% parks_per_places$GEOID) %>%
#   st_set_geometry(NULL) %>% 
#   left_join(., state_identifiers, by = c("STATEFP" ="state_code")
#             ) %>%
#   select(NAME, state)
# )


places_without_parks_reactable <- reactable(places %>% 
  filter(!GEOID %in% parks_per_places$GEOID) %>%
  st_set_geometry(NULL) %>% 
  left_join(., state_identifiers, by = c("STATEFP" ="state_code")
            ) %>%
  select(Name = "NAME", State = "state"), 
  searchable = TRUE, 
  filterable = TRUE,
  striped = TRUE,
  highlight = TRUE,
  minRows = 10)


div(class = "places_without_parks_reactable",
  div(class = "places_without_parks_reactable-header",
      h3(class = "places_without_parks_reactable-title", "Places without Parks"),
     places_without_parks_reactable
  )
)

Places without Parks

Maps for Select Regions

Chicago

Chicago has the most parks. The number of green-ways, (i.e., green areas between major roadways), particularly on the western side of the city is striking.

chicago <- places %>%
  filter(NAME == "Chicago") %>%
  compute_area_sqmi(.)

chicago_parks <- usa_parks_prj %>% 
  st_intersection(., chicago %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    )
  
leaflet() %>% 
addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>% 
  addPolygons(
    data = chicago %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>%
  addPolygons(
    data = chicago_parks %>% st_transform(., wgs),
    label = ~NAME,
    fillColor = "green",
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7
  )

Although there are many parks in Chicago, they tend to be small in size. The average park area is 0.03 square miles. The largest park is 1.27 square miles. In total, park space makes up 17.05 square miles in Chicago, which is approximately 7% of the city’s land area.

summary(chicago_parks$area_sqmi)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
0.0000016 0.0012127 0.0048438 0.0298077 0.0160233 1.2702983 

Most of Chicago’s parks are local. 2 are county and 3 are regional.

knitr::kable(chicago_parks %>% 
               st_set_geometry(NULL) %>%
               select(FEATTYPE) %>%
               count(FEATTYPE) %>%
               arrange(-n),
             col.names = c("Type of Park", "Freq."),
             caption = "Count of Parks in Chicago.",
             format.args = list(big.mark = ",")
             )
Count of Parks in Chicago.
Type of Park Freq.
Local park 566
Regional park 3
County park 2
State park or forest 1
Philadelphia
philly <- places %>%
  filter(NAME == "Philadelphia" & STATEFP == "42") %>%
  compute_area_sqmi(.)

philly_parks <- usa_parks_prj %>% 
  st_intersection(., philly %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    )
  
leaflet() %>% 
addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = philly %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>%
  addPolygons(
    data = philly_parks %>% st_transform(., wgs),
    label = ~NAME,
    fillColor = "green",
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7
  )
San Antonio
san_antonio <- places %>%
  filter(NAME == "San Antonio" & STATEFP == "48") %>%
  compute_area_sqmi(.)

san_antonio_parks <- usa_parks_prj %>% 
  st_intersection(., san_antonio %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    )
  
leaflet() %>% 
addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = san_antonio %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>%
  addPolygons(
    data = san_antonio_parks %>% st_transform(., wgs),
    label = ~NAME,
    fillColor = "green",
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7
  )
San Francisco
san_francisco <- places %>%
  filter(NAME == "San Francisco" & STATEFP == "06") %>%
  compute_area_sqmi(.)

san_francisco_parks <- usa_parks_prj %>% 
  st_intersection(., san_francisco %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    )
  
leaflet() %>% 
addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = san_francisco %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>%
  addPolygons(
    data = san_francisco_parks %>% st_transform(., wgs),
    label = ~NAME,
    fillColor = "green",
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7
  )
Hialeah

Hialeah is among the top 100 cities by population size as of 2010. Among the top 100 cities, Hialeah has the lowest amount of park area. There are 17 parks in Hialeah. All of these parks are locally maintained and owned.

hialeah <- places %>%
  filter(NAME == "Hialeah") %>%
  compute_area_sqmi(.)

hialeah_parks <- usa_parks_prj %>% 
  st_intersection(., hialeah %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    )
  
leaflet() %>% 
  addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = hialeah %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>% 
  addPolygons(
    data = hialeah_parks %>% st_transform(., wgs),
    label = ~NAME,
    fillColor = "green",
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7
  )

The parks cover small amounts of area. The average park size in Hialeah is 0.01 square miles, and the largest park spans about 0.04 miles.

summary(hialeah_parks$area_sqmi)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
0.0003552 0.0043941 0.0085464 0.0139106 0.0189954 0.0420502 
Eau Claire

Eau Claire, Wisconsin is another city with very low park coverage.

eau_claire <- places %>%
  filter(NAME == "Eau Claire" & STATEFP == "55") %>%
  compute_area_sqmi(.)

eau_claire_parks <- usa_parks_prj %>% 
  st_intersection(., eau_claire %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    )

leaflet() %>% 
  addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = eau_claire %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>% 
  addPolygons(
    data = eau_claire_parks %>% st_transform(., wgs),
    label = ~NAME,
    fillColor = "green",
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7
  )

Parks by County

## Create parks per county dataset 
# parks_per_county <-  usa_parks_prj %>% 
#   st_intersection(., counties %>% st_transform(., albersea)
#                   ) %>%
#   post_intersection_cleaning(.) %>%
#   left_join(., counties, by = "GEOID")
# saveRDS(parks_per_county, "parks_per_county_2021.rds")
parks_per_county <- readRDS("parks_per_county_2021.rds")


## compute area of places
counties_area <- counties %>% 
  compute_area_sqmi(.)
#61,569 park count
## create table
parks_per_county_reactable <- reactable(parks_per_county %>% 
  create_paged_table_view(.) %>% 
    mutate(total_park_area_sqmi = round(total_park_area_sqmi, digits = 2),
           percent_of_land_area = percent(percent_of_land_area, accuracy = 0.01,
                                                scale = 1, suffix = "%" 
                                                 )
           ) %>%
  rename(County = "NAME",
         State = "state",
         Parks = "parks", 
         'Area (Sq Mi)' = "total_park_area_sqmi",
         'Percent of Land Cover' = "percent_of_land_area"), 
  searchable = TRUE,
  filterable = TRUE,
  striped = TRUE,
  highlight = TRUE,
  minRows = 10
  )

div(class = "parks_per_county_reactable",
  div(class = "parks_per_county_reactable-header",
      h3(class = "parks_per_county_reactable-title", "Parks by County"),
     parks_per_county_reactable
  )
)

Parks by County

# FIND COUNTIES WITHOUT PARK SPACE
counties_without_parks_reactable <- reactable(counties %>% 
  filter(!GEOID %in% parks_per_county$GEOID) %>%
  st_set_geometry(NULL) %>% 
  left_join(., state_identifiers, by = c("STATEFP" ="state_code")
            ) %>%
  select(County = "NAME", State = "state"), 
  searchable = TRUE, 
  filterable = TRUE,
  striped = TRUE,
  highlight = TRUE,
  minRows = 10)


div(class = "counties_without_parks_reactable",
  div(class = "counties_without_parks_reactable-header",
      h3(class = "counties_without_parks_reactable-title", "Counties without Parks"),
     counties_without_parks_reactable
  )
)

Counties without Parks

Parks by Metros

## Create parks by metros dataset
# parks_per_metro <-  usa_parks_prj %>%
#   st_intersection(., metros10 %>% st_transform(., albersea)
#                   ) %>%
#   mutate(
#     intersection_area = st_area(.),
#     area_sqmi = as.numeric(set_units(intersection_area, mi^2))
#     ) %>%
#   group_by(GEOID10) %>%
#   summarize(parks = n(),
#             total_park_area = sum(SQMI),
#             total_park_area_sqme = sum(intersection_area),
#             total_park_area_sqmi = sum(area_sqmi)
#             )  %>%
#   st_set_geometry(NULL) %>%
#   left_join(., metros10, by = "GEOID10")
# saveRDS(parks_per_metro, "parks_per_metro_2021.rds")
parks_per_metro <- readRDS("parks_per_metro_2021.rds")

metros10_area <- metros10 %>%
  compute_area_sqmi(.)
##st_intersection version
rmarkdown::paged_table(parks_per_metro %>% 
  select(parks, total_park_area_sqmi, NAME10, GEOID10) %>%
  arrange(-parks) %>%
  left_join(., metros10_area %>% select(GEOID10, area_sqmi), by = "GEOID10") %>%
  mutate(percent_of_land_area = (total_park_area_sqmi/area_sqmi) * 100) %>%
  select(NAME10, parks, total_park_area_sqmi, percent_of_land_area) %>%
  mutate(total_park_area_sqmi = round(total_park_area_sqmi, digits = 2),
         percent_of_land_area = percent(percent_of_land_area, accuracy = 0.01,
                                              scale = 1, suffix = "%"
                                               ), 
         parks = format(parks, big.mark = ",")
         ) %>%
  rename(Region = "NAME10",
         Parks = "parks",
         'Area (sq mi.)' = "total_park_area_sqmi",
         'Percent of Land Cover' = "percent_of_land_area"
         )
)
## FIND METROS/MICROS WITHOUT PARK SPACE
metros_without_parks_reactable <- reactable(metros10 %>%
  filter(!GEOID10 %in% parks_per_metro$GEOID10) %>% 
  st_set_geometry(NULL) %>%
  select(GEOID10:NAMELSAD10), 
  searchable = TRUE, 
  filterable = TRUE,
  striped = TRUE,
  highlight = TRUE,
  minRows = 10)


div(class = "metros_without_parks_reactable",
  div(class = "metros_without_parks_reactable-header",
      h3(class = "metros_without_parks_reactable-title", "Metros without Parks"),
     metros_without_parks_reactable
  )
)

Metros without Parks

Demographics & Distribution of Parks

Parks Aggregated to Philadelphia Block Groups

# CROP CBGs TO SELECT LOCATIONS 
philly_county_cbg <- cbg10 %>% 
  filter(STATEFP10 == "42" & COUNTYFP10 == "101")
  
bexar_county_cbg <- cbg10 %>%
  filter(STATEFP10 == "48" & COUNTYFP10 == "029")


parks_per_philly_cbgs <-  usa_parks_prj %>%
  st_intersection(., philly_county_cbg %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    ) %>%
  group_by(GEOID10) %>%
  summarize(parks = n(),
            total_park_area = sum(SQMI),
            total_park_area_sqme = sum(intersection_area),
            total_park_area_sqmi = sum(area_sqmi)
            )  %>%
  mutate_if(is.numeric, ~replace(., is.na(.), 0))
parks_per_philly_cbgs <- parks_per_philly_cbgs %>%
  st_set_geometry(NULL)

parks_per_bexar_cbgs <-  usa_parks_prj %>%
  st_intersection(., bexar_county_cbg %>% st_transform(., albersea)
                  ) %>%
  mutate(
    intersection_area = st_area(.),
    area_sqmi = as.numeric(set_units(intersection_area, mi^2))
    ) %>%
  group_by(GEOID10) %>%
  summarize(parks = n(),
            total_park_area = sum(SQMI),
            total_park_area_sqme = sum(intersection_area),
            total_park_area_sqmi = sum(area_sqmi)
            )  %>%
  mutate_if(is.numeric, ~replace(., is.na(.), 0))
parks_per_bexar_cbgs <- parks_per_bexar_cbgs %>%
  st_set_geometry(NULL)

# ADD GEOMETRY TO SELECT LOCATIONS 
parks_per_philly_cbgs <- philly_county_cbg %>%
  left_join(., parks_per_philly_cbgs, by = "GEOID10") %>%
  mutate_if(is.numeric, ~replace(., is.na(.), 0))

parks_per_bexar_cbgs <- bexar_county_cbg %>%  
  left_join(., parks_per_bexar_cbgs, by = "GEOID10") %>%
  mutate_if(is.numeric, ~replace(., is.na(.), 0))

philly_pal <- colorNumeric(
  palette = "Greens",
  domain = parks_per_philly_cbgs$parks
)
philly_area_pal <- colorNumeric(
  palette = "Greens",
  domain = parks_per_philly_cbgs$total_park_area_sqmi
)

leaflet() %>% 
  addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = philly %>% st_transform(., wgs),
    fillColor = "transparent",
    color = "black"
  ) %>% 
  addPolygons(
    data = parks_per_philly_cbgs %>% st_transform(., wgs),
    label = ~parks,
    fillColor = ~philly_pal(parks),
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7,
    group = "Number of Parks"
  )  %>% 
  addPolygons(
    data = parks_per_philly_cbgs %>% st_transform(., wgs),
    label = ~paste0(format(total_park_area_sqmi, digits = 2, big.mark = ","), " mi^2"),
    fillColor = ~philly_area_pal(parks),
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7,
    group = "Park Area"
  ) %>% 
  addLayersControl(
    overlayGroups = c("Number of Parks", "Park Area"),
    position = "topright",
    options = layersControlOptions(collapsed = F)
) %>%
  addLegend("bottomright", pal = philly_pal, title="Number of Parks",
            values = parks_per_philly_cbgs$parks, group="Number of Parks") %>%
  addLegend("bottomright", pal = philly_area_pal, title="Park Area (Sq Mi.)",
            values = parks_per_philly_cbgs$total_park_area_sqmi, group="Park Area")

Parks Aggregated to Bexar County, TX Census Block Groups

San Antonio, TX is the county seat. The city of San Antonio is not coterminous with Bexar County. Note: Return and clip to San Antonio city limits

bexar_pal <- colorNumeric(
  palette = "Greens",
  domain = parks_per_bexar_cbgs$parks
)
bexar_area_pal <- colorNumeric(
  palette = "Greens",
  domain = parks_per_bexar_cbgs$total_park_area_sqmi
)

leaflet() %>% 
  addMapboxTiles(
    style_id = "streets-v11",
    username = "mapbox"
  ) %>%
  addPolygons(
    data = parks_per_bexar_cbgs %>% st_transform(., wgs),
    label = ~parks,
    fillColor = ~bexar_pal(parks),
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7,
    group = "Number of Parks"
  )  %>% 
  addPolygons(
    data = parks_per_bexar_cbgs %>% st_transform(., wgs),
    label = ~paste0(format(total_park_area_sqmi, digits = 1, big.mark = ","), " mi^2"),
    fillColor = ~bexar_area_pal(parks),
    weight = 2,
    opacity = 1,
    color = "black",
    fillOpacity = 0.7,
    group = "Park Area"
  ) %>% 
  addLayersControl(
    overlayGroups = c("Number of Parks", "Park Area"),
    position = "topright",
    options = layersControlOptions(collapsed = F)
) %>%
  addLegend("bottomright", pal = bexar_pal, title="Number of Parks",
            values = parks_per_bexar_cbgs$parks, group="Number of Parks") %>%
  addLegend("bottomright", pal = bexar_area_pal, title="Park Area (Sq Mi.)",
            values = parks_per_bexar_cbgs$total_park_area_sqmi, group="Park Area")
# Avg PS per Min nhood, Avg PS per white nhood
# MedHHINC of nhoods with parks